package com.zyh.cxf.Interceptor;

import java.io.*;

import java.text.SimpleDateFormat;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;

import com.zyh.dao.KeyMapper;
import com.zyh.util.ConfigInfo;
import com.zyh.util.safeutil.DESedeUtil;
import com.zyh.util.safeutil.SM2Utils;
import com.zyh.util.safeutil.Util;
import org.apache.cxf.binding.soap.SoapMessage;

import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.transport.http.AbstractHTTPDestination;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;


/**
 * WebService的输入拦截器
 * @author coisini
 * @date May 2020, 13
 *
 */
@Component("InServiceInInterceptor")
public class WebServiceInInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

	@Autowired
	private KeyMapper keyMapper;

	private static final String USERNAME = "admin";
    private static final String PASSWORD = "P@ssw0rd";
    
    /**
     * 允许访问的IP
     */
    private static final String ALLOWIP = ConfigInfo.getIPConfigInfoByName("esb-Ips");   //"127.0.0.1;XXX.XXX.XXX.XXX";  String ip = ConfigInfo.getConfigInfoByName("esb.server.ip");

	//String port = ConfigInfo.getConfigInfoByName("esb.server.port");

	public WebServiceInInterceptor() {
		/*
		 * 拦截器链有多个阶段，每个阶段都有多个拦截器，拦截器在拦截器链的哪个阶段起作用，可以在拦截器的构造函数中声明
		 * RECEIVE 接收阶段，传输层处理
		 * (PRE/USER/POST)_STREAM 流处理/转换阶段
		 * READ SOAPHeader读取 
		 * (PRE/USER/POST)_PROTOCOL 协议处理阶段，例如JAX-WS的Handler处理 
		 * UNMARSHAL SOAP请求解码阶段 
		 * (PRE/USER/POST)_LOGICAL SOAP请求解码处理阶段 
		 * PRE_INVOKE 调用业务处理之前进入该阶段 
		 * INVOKE 调用业务阶段 
		 * POST_INVOKE 提交业务处理结果，并触发输入连接器
		 */
		super(Phase.PRE_INVOKE);
//		super(Phase.RECEIVE);
		
	}

	/**
	  * 客户端传来的 soap 消息先进入拦截器这里进行处理，客户端的账目与密码消息放在 soap 的消息头<security></security>中，
	  * 类似如下：
     * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
     * <soap:Header><security><username>admin</username><password>P@ssw0rd</password></security></soap:Header>
     * <soap:Body></soap:Body></soap:Envelope>
     * 现在只需要解析其中的 <head></head>标签，如果解析验证成功，则放行，否则这里直接抛出异常，
     * 服务端不会再往后运行，客户端也会跟着抛出异常，得不到正确结果
     *
     * @param message
     * @throws Fault
     */
	@Override
    public void handleMessage(SoapMessage message) throws Fault {


		//拦截器中判断 PayerAcNo 是否是维护好的 账户



		HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
		List<String> list = message.getContent(List.class);
		String ipAddr = request.getRemoteAddr();
		System.out.println("客户端访问IP----" + ipAddr);
		System.out.println("PRE_INVOKE");

		Exchange exchange = message.getExchange();
		BindingOperationInfo bop = exchange.getBindingOperationInfo();

		String invoteMehtod = bop.getInput().getMessageInfo().toString();//[MessageInfo INPUT: {http://cxf.zyh.com/}getABalanceDes]
		String invoteArgs = "";


		for (int len = 0; len < list.size(); len++) {

			invoteArgs = list.get(len);
		}


		//账户判断 ALLOWACNO

		// 拿到请求报文中的 	mapQRC01.put("PayerAcNo", PayerAcNO);

/*
		Map mapRequest = doRequestObj(invoteArgs);
		String acNoStr = (String) mapRequest.get("PayerAcNo");
		String[] acNoStrs = ALLOWACNO.split(";");
		Boolean isExistAcNo = false;

		for (int i = 0; i < acNoStrs.length; i++) {


			if (acNoStrs[i].equals(acNoStr)) {
				isExistAcNo = true;
				break;
			}
		}

		if (!isExistAcNo) {

			List<Header> headers = message.getHeaders();

			Document doc = DocumentHelper.createDocument();
			Element Message = doc.addElement("Message");
			Element Head = Message.addElement("Head");
			Element Body = Message.addElement("Body");


//			Element serialNo = Head.addElement("serialNo");
//			Element reqTime = Head.addElement("reqTime");
//
//			serialNo.setText("1");
//			reqTime.setText("20201217");

			Element PayerAcNO = Body.addElement("PayerAcNo");


			PayerAcNO.setText("对公账户规则‘8’开头");// 82010000000369927  131657-error: 没有找到符合条件的记录！


			headers.add(new Header(new QName("0009"),doc));

			return ;

			//throw new Fault(new IllegalArgumentException("对公账户规则‘8’开头"), new QName("0009"));
		}

  */




		//写入 requestSoap.log日志文件

		FileWriter fw = null;
		PrintWriter pw = null;


		try {
			String pathStr = this.getClass().getClassLoader().getResource("").getPath() + "requestxml.log";

			String pathstrT = request.getSession().getServletContext().getRealPath("/");

			pathstrT += "requestxml.log";

			pathstrT = System.getProperty("catalina.home");
			pathstrT += "requestxml.log";
			File f = new File(pathstrT);

			fw = new FileWriter(f, true);
			pw = new PrintWriter(fw);
			pw.println("IP:" + ipAddr + "   " + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()).toString() + ":" + invoteMehtod + "   XML:" + invoteArgs);

			pw.println("--------------------------------------\r\n");
			pw.flush();


		} catch (IOException e) {
			e.printStackTrace();
		} finally {

			try {
				fw.flush();
				pw.close();
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}


		}

		//写入 requestSoap.log日志文件
		String[] ipStrs = ALLOWIP.split(";");
		Boolean isExist = false;

		for (int i = 0; i < ipStrs.length; i++) {


			if (ipStrs[i].equals(ipAddr)) {
				isExist = true;
			}
		}

			if (!isExist) {

				throw new Fault(new IllegalArgumentException("非法IP地址"), new QName("0009"));
			}

			/**
			 * org.apache.cxf.headers.Header
			 * QName ：xml 限定名称，客户端设置头信息时，必须与服务器保持一致，否则这里返回的 header 为null，则永远通不过的
			 */

		/*
		Header authHeader = null;
		//获取验证头
		List<Header> headers = message.getHeaders();
		for(Header h:headers){
			if(h.getName().toString().contains("security")){
				authHeader=h;
				break;
			}
		}
		System.out.println("authHeader");
		System.out.println(authHeader);

		/*
		if(authHeader !=null) {
			Element auth = (Element) authHeader.getObject();
			NodeList childNodes = auth.getChildNodes();
			String username = null,password = null;
			for(int i = 0, len = childNodes.getLength(); i < len; i++){
					Node item = childNodes.item(i);
					if(item.getNodeName().contains("username")){
						username = item.getTextContent();
						System.out.println(username);
					}
					if(item.getNodeName().contains("password")){
						password = item.getTextContent();
						System.out.println(password);
					}
			}

			if(StringUtils.isBlank(username) || StringUtils.isBlank(password)) { 
		    	throw new Fault(new IllegalArgumentException("用户名或密码不能为空"), new QName("0001")); 
		    }else{
				System.out.println("webService 服务端自定义拦截器验证通过(server)....");
				return;//放行
			}

			if(!Sm3Utils.verify(USERNAME, username) || !Sm3Utils.verify(PASSWORD,password)) { 
		    	throw new Fault(new IllegalArgumentException("用户名或密码错误"), new QName("0008")); 
		    }



		}else {
			throw new Fault(new IllegalArgumentException("请求头security不合法"), new QName("0010"));
		}
		*/
		}

	// 出现错误输出错误信息和栈信息
	public void handleFault(SoapMessage message) {
		Exception exeption = message.getContent(Exception.class);
		System.out.println(exeption.getMessage());
	}

	//解析医保端请求方的XML数据
	private Map<String, String> doRequestObj(String xmlData) {

		//先进行解密
		Map<String, Object> keyMap = keyMapper.querykey();
		//查询加密的公钥
		String inencryptKey=(String)keyMap.get("PublicKey");
		String privateKey=(String)keyMap.get("PrivateKey");
		//第一步密钥解密
		System.err.println("密钥sm2私钥解密：");
		String plainText = null;
		try {
			plainText = new String(SM2Utils.decrypt(Util.hexToByte(privateKey), Util.hexToByte(inencryptKey)));
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("密钥明文：" + plainText);
		// 第二步通过拿到的解密密钥进行报文解密
		String inresource = null;
		try {
			inresource = DESedeUtil.decrypt(xmlData, plainText);
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println("医保端明文："+ inresource);

		Map<String, String> mapQRC01 = new HashMap<>();
		Document doc = null;
		try {
			doc = DocumentHelper.parseText(inresource);
			Element rootElt = doc.getRootElement();

//			// 只返回 Head 内容
//			Iterator itersHead = rootElt.elementIterator("Head");
//
//			while (itersHead.hasNext()) {
//
//				Element reEless = (Element) itersHead.next();
//				String serialNo = reEless.elementTextTrim("serialNo");
//				String reqTime = reEless.elementTextTrim("reqTime");
//
//				mapQRC01.put("serialNo", serialNo);
//				mapQRC01.put("reqTime", reqTime);
//
//			}

			// 只返回 Body 内容
			Iterator itersBody = rootElt.elementIterator("Body");
			while (itersBody.hasNext()) {

				Element reEless = (Element) itersBody.next();
				//账户流水查询用账户号【解析传入】PayerAcNo
				String PayerAcNO = reEless.elementTextTrim("PayerAcNo");
				String PayeeAcNo = reEless.elementTextTrim("PayeeAcNo");

				String BeginDate = reEless.elementTextTrim("BeginDate");
				String EndDate = reEless.elementTextTrim("EndDate");

				String PayerCurrency = reEless.elementTextTrim("PayerCurrency");

				mapQRC01.put("PayerAcNo", PayerAcNO);
				mapQRC01.put("PayerCurrency", PayerCurrency);

				mapQRC01.put("BeginDate", BeginDate);
				mapQRC01.put("EndDate", EndDate);
				mapQRC01.put("PayeeAcNo",PayeeAcNo);

			}


		} catch (DocumentException e) {
			System.out.println(e.getMessage());
		}

		return mapQRC01;
	}


}
